/**
 * 角色管理
 * by @author lms 2022.07.27
 */
package ms.core.gateway.utils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import ms.core.common.AppException;
import ms.core.common.Page;
import ms.core.common.consts.SysErr;
import ms.core.db.mysql.DbUtilsDrv;
import ms.core.gateway.bean.SysCorpBean;
import ms.core.gateway.bean.SysRoleBean;
import ms.core.gateway.dao.SysRoleDao;
import ms.core.gateway.request.*;
import ms.core.gateway.response.SysRoleVO;
import ms.core.gateway.tool.SessionTool;
import ms.core.tool.StrTool;

public class SysRoleUtils {
	private SysRoleDao dao;
	public SysRoleUtils() { dao = new SysRoleDao(); }

	/**
	 * 新增角色
	 * 
	 * @param role
	 * @return
	 */
	public SysRoleVO newRole(CreateRoleRequest role) {
		if (SysCorpUtils.getCorp(role.getCorpUid())==null)
			throw new AppException(SysErr.SYS_DATA_NOT_FOUND, "无此添加角色企业.");

		SysRoleBean exist = dao.getRole(role.getCorpUid(), role.getRoleName(), SysRoleBean.class);
		if (exist!=null)
			throw new AppException(SysErr.USER_ROLE_EXISTS, "角色已存在");

		dao.newRole(role, null);
		return dao.getRole(role.getCorpUid(), role.getRoleName(), SysRoleVO.class);
	}
	
	/**
	 * 修改角色(涉及角色和用户表修改,需采用事务保护)
	 * 
	 * @param corpUid
	 * @param role
	 * @return 新增角色,返回新增角色对象;修改角色,返回旧的角色对象
	 */
	public SysRoleVO editRole(String corpUid, UpdateRoleRequest role) {
		try {
			DbUtilsDrv.startTransaction();
			
			SysRoleBean exist = dao.getRole(role.getId());
			if (exist==null || (!StrTool.isBlank(corpUid) && !exist.getCorpUid().equals(corpUid)))
				throw new AppException(SysErr.SYS_DATA_NOT_FOUND, "企业无此待修改角色");

			// 判断角色是否冲突
			SysRoleBean conflict = dao.getRole(exist.getCorpUid(), role.getRoleName(), SysRoleBean.class);
			if (conflict!=null && conflict.getId()!=role.getId()) 
				throw new AppException(SysErr.SYS_DATA_EXISTS, "角色已存在");

			// 1.角色名发生变更,则需要更新已分配用户角色
			boolean roleAlter = !exist.getRoleName().equalsIgnoreCase(role.getRoleName());
			if (roleAlter) SysUserUtils.updateRole(exist.getCorpUid(), exist.getRoleName(), role.getRoleName());

			// 2.修改角色
			dao.editRole(role);

			// 3.更新在线用户角色名称
			if (roleAlter) SessionTool.updateCorpUserRole(exist.getCorpUid(), exist.getRoleName(), role.getRoleName());

			DbUtilsDrv.commitTransaction();
			
			return dao.getRecord(role.getId(), SysRoleVO.class);
		} catch (AppException e) {
			DbUtilsDrv.rollTransaction();
			throw new AppException(e);
		}
	}
	
	/**
	 * 删除角色
	 * 
	 * @param corpUid
	 * @param id
	 * @return
	 */
	public void deleteRole(String corpUid, long id) {
		SysRoleBean role = dao.getRole(id);
		if (role==null || (!StrTool.isBlank(corpUid)) && !role.getCorpUid().equals(corpUid)) 
			throw new AppException(SysErr.SYS_DATA_NOT_FOUND, "企业无此角色");

		if (role.getRoot()==SysRoleBean.ROLE_ROOT) 
			throw new AppException(SysErr.USER_ADMIN_ROLE, "系统主角色，不可删除");

		try {
			DbUtilsDrv.startTransaction();
			// 1.删除角色
			dao.deleteRole(id);
			// 2.回收用户拥有该角色帐户对应角色
			SysUserUtils.removeRole(role.getCorpUid(), role.getRoleName());
			// 3.移除企业在线用户拥有该角色权限
			SessionTool.removeCorpUserRoleFuncs(role.getCorpUid(), role.getRoleName());
			
			DbUtilsDrv.commitTransaction();
		} catch(AppException e) {
			DbUtilsDrv.rollTransaction();
			throw new AppException(e);
		}
	}

	/**
	 * 角色授权
	 * 
	 * @param corpUid 企业id
	 * @param id 角色id
	 * @param funcs 授予功能列表
	 * @return
	 */
	public void authRoleFuncs(String corpUid, long id, List<String> funcs) {
		// 角色有效性验证
		SysRoleBean role = dao.getRole(id);
		if (role==null || !role.getCorpUid().equals(corpUid)) 
			throw new AppException(SysErr.SYS_DATA_NOT_FOUND, "无此角色");

		SysCorpBean corp = SysCorpUtils.getCorp(corpUid);
		if (corp==null)
			throw new AppException(SysErr.SYS_DATA_NOT_FOUND, "授权的角色无企业信息.");
		
		// 加载对应类型用户的所有权限
		List<String> list = SysFuncUtils.loadFuncs(corp.getCtype());
		// 过滤非法的权限
		int i=0;
		while (i<funcs.size()) {
			if (!list.contains(funcs.get(i))) funcs.remove(i);
			else i++;
		}

		if (funcs.size()==0) 
			throw new AppException(SysErr.SYS_PARAM_ERR, "未授予有效功能权限或系统未配置功能表");

		// 保存角色权限
		dao.authFuncs(id, funcs);
		// 更新企业在线用户拥有该角色权限
		SessionTool.refreshCorpUserRoleFuncs(corpUid, role.getRoleName());
	}

	/**
	 * 角色查询
	 * 
	 * @param corpId
	 * @param roles
	 * @return
	 */
	public Page<SysRoleVO> queryRole(QueryRoleRequest req) {
		return dao.queryRole(req);
	}	

	// --------------------------------------- static functions --------------------------------------- //

	/**
	 * 创建企业管理员角色
	 * 
	 * @param corpUid
	 * @param utype
	 * @param renew 是否刷新 admin 权限
	 */
	public static void createAdminRole(String corpUid, int utype, boolean renew) {
		CreateRoleRequest role = new CreateRoleRequest();
		role.setCorpUid(corpUid);
		role.setRoleName(SysRoleBean.ROLE_ADMIN);
		List<String> funcs = SysFuncUtils.loadFuncs(utype);
		role.setRoot(SysRoleBean.ROLE_ROOT);
		role.setRemark("系统内置");

		SysRoleDao dao = new SysRoleDao();
		SysRoleBean exist = dao.getRole(corpUid, SysRoleBean.ROLE_ADMIN, SysRoleBean.class);
		if (exist!=null) {
			if (renew) {
				dao.authFuncs(exist.getId(), funcs);
			}
			return;
		}

		dao.newRole(role, funcs);
	}

	/**
	 * 获取企业角色列表
	 * 
	 * @param corpId
	 * @return
	 */
	public static List<SysRoleVO> queryRole(String corpId) {
		SysRoleDao dao = new SysRoleDao();
		return dao.queryRoles(corpId, null, null);
	}	

	/**
	 * 获取角色对应权限列表
	 * 
	 * @param corpId
	 * @param roles
	 * @return
	 */
	public static List<String> getRoleFuncs(String corpId, List<String> roles) {
		Set<String> funcs = new HashSet<>();
		SysRoleDao dao = new SysRoleDao();
		List<SysRoleVO> list = dao.queryRoles(corpId, roles, null);
		if (list!=null && list.size()>0) {
			for(int i=0; i<list.size(); i++) {
				funcs.addAll(list.get(i).getFuncList());
			}
		}

		return new ArrayList<>(funcs);
	}
	
	public static void main(String[] args) {
		createAdminRole("309b44730a8048af9e8ccca01de2fb8c", 2, true);
	}
}
